import { showNotify } from '@nutui/nutui'
import '@nutui/nutui/dist/packages/notify/style'
import axios, { AxiosInstance, AxiosRequestConfig, AxiosError, AxiosResponse, Cancel, Canceler, AxiosPromise } from 'axios'
import siStore from 'si-store'
// console.log(import.meta.env.MODE)

// function isObject(obj: any): boolean {
//     return Object.prototype.toString.call(obj) === '[object Object]'
// }

if (import.meta.env.VITE_APP_ENV === 'local') {
    const testToken = siStore.get('tokenData') || {}
    if (!testToken.access_token) {
        //取本地的token。没有的话设置一个空的，然后去浏览器填进去
        siStore.set('tokenData', { 'access_token': '', 'token_type': 'bearer' })
    }
}

class AxiosRequest {
    public instance: AxiosInstance
    private pendingRequest: Map<string, Canceler> = new Map()
    private maxRetryCount: number
    private retryDelay: number
    static tenant: string
    public constructor() {
        console.log('请求地址', import.meta.env.VITE_BASE_API)
        this.instance = axios.create({
            baseURL: import.meta.env.VITE_BASE_API,
            timeout: 60000,
            responseType: 'json'
        })
        this.maxRetryCount = 0
        this.retryDelay = 2000
        this.addRequestInterceptors()
        this.addResponseInterceptors()
    }

    /**
   * 把请求配置里关键的项使用'&'拼成字符串
   * @param config axios请求配置
   * @returns axios请求配置里url、method、params、data使用&拼成的字符串
   */
    private getRequestUrl(config: AxiosRequestConfig): string {
        return [config.method, config.url, JSON.stringify(config.params), JSON.stringify(config.data)].join('&')
    }


    /**
   * 添加请求拦截器
   */
    private addRequestInterceptors(): void {
        this.instance.interceptors.request.use((config) => {
            // this.sortOrderFormat(config)
            this.setHeader(config)
            this.removeRepeatRequest(config)
            this.addPendingRequest(config)
            return config
        }, error => {
            Promise.reject(error)
        })
    }

    /**
   * 添加响应拦截器
   */
    private addResponseInterceptors(): void {
        this.instance.interceptors.response.use((response: AxiosResponse<{ code: number, message: string, data: any }>) => {
            // 从pendingRequest里移除该次请求
            // console.log(response)
            const url = this.getRequestUrl(response.config)
            this.pendingRequest.delete(url)
            if (response.data) {
                // UserModule.ResetToken()
                // this.clearPendingRequest()
            }
            return response

        }, (error: AxiosError<AxiosResponse, AxiosType>) => {
            console.log(error)
            const config = error.config as AxiosType
            // 处理取消请求返回的错误信息，此时该请求已经从pendingRequest中移除了
            if (!error.config) {
                return Promise.reject({
                    code: Number((error as Cancel).message)
                })
            }
            // console.log(error)
            // 从pendingRequest里移除该次请求
            const url = this.getRequestUrl(error.config)
            this.pendingRequest.delete(url)

            // 处理未授权的情况
            // 重置Token，弹出mini登录页
            if (error.response) {
                const errorRes = error.response?.data || { message: error.message, code: error.response?.status }
                if (error.response.status === 401) {
                    // 401
                    this.clearPendingRequest()
                    return Promise.reject(errorRes)
                } else if (error.response.status === 440) {
                    // 440 权限失效
                    this.clearPendingRequest()
                    return Promise.reject({ message: '登录Token失效', code: 440 })
                } else if (error.response.status === 500) {
                    // 500
                    this.clearPendingRequest()
                    if (!config.isReturnMsg) {
                        showNotify.danger(errorRes.message)
                        // showDialog({
                        //     overlayStyle: { background: 'rgba(0,0,0,0.5)' },
                        //     title: '错误提示',
                        //     content: errorRes.message,
                        //     noCancelBtn: true,
                        //     onOk
                        // })
                    }
                    return Promise.reject(errorRes)
                } else {
                    // 或者其他报错
                    this.clearPendingRequest()
                    if (!config.isReturnMsg) {
                        showNotify.danger('(http code:' + error.response.status + ')' + errorRes.message)
                    }
                    return Promise.reject(errorRes)
                }
            } else {
                this.clearPendingRequest()
                enum errorMessageMap {
                    ERR_NETWORK = '网络错误',
                    ECONNABORTED = '网关超时'
                }
                if (!config.isReturnMsg) {
                    showNotify.danger(error.message || errorMessageMap[error.code as 'ERR_NETWORK' | 'ECONNABORTED'])
                }
                return Promise.reject({
                    code: error.code,
                    message: error.message
                })
            }

            // 如果不进行请求重试就直接结束promise
            // if (!this.allowErrorRetryCodes.includes(error.response?.status ?? 503) || this.maxRetryCount === 0) {
            //     return Promise.reject({
            //         code: error.response?.status
            //     })
            // }
            // 请求重试
            // console.log(error, 'error')
            // return this.requestRetry(error)
        }
        )
    }




    /**
   * 把参数中的order排序字段转换成后端需要的格式
   * @param config
   */
    private sortOrderFormat(config: AxiosRequestConfig): void {
        if (config.data?.order) {
            config.data.order = config.data.order === 'ascending' ? 'asc' : 'desc'
        }
    }


    /**
   * 取消所有请求
   */
    public clearPendingRequest(): void {
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        // for (const [url, cancel] of this.pendingRequest) {
        //     console.log(url)
        //     cancel(CustomerCancelCodeEnum.cancelRequest)
        // }
        this.pendingRequest.clear()
    }


    /**
   * 把该次请求加入存放pending状态的map中
   * @param config
   */
    private addPendingRequest(config: AxiosType): void {
        const url = this.getRequestUrl(config)
        config.cancelToken =
            config.cancelToken ||
            new axios.CancelToken(cancel => {
                if (!this.pendingRequest.has(url)) {
                    // 如果 pending 中不存在当前请求，则添加进去
                    this.pendingRequest.set(url, cancel)
                }
            })
    }


    /**
   * 取消重复请求
   * @param config
   */
    private removeRepeatRequest(config: AxiosType): void {
        if (config.repeat) {
            return
        }
        // const url = this.getRequestUrl(config)
        // if (this.pendingRequest.has(url)) {
        //     // 如果该请求之前已发送过，并且还未结束，则取消之前的请求，并且从map中移除
        //     const cancel = this.pendingRequest.get(url)!
        //     cancel(CustomerCancelCodeEnum.cancelOftenRequest)
        //     this.pendingRequest.delete(url)
        // }
    }



    /**
   * 请求重试
   * @param error any
   * @returns axios实例
   */
    private requestRetry(error: AxiosError<AxiosResponse>): AxiosPromise<AxiosInstance> {
        const config: any = error.config
        // 把用于跟踪重试计数的变量加到config内
        config.__retryCount = config.__retryCount || 0
        // 检查是否已经把重试的总数用完
        if (config.__retryCount >= this.maxRetryCount) {
            return Promise.reject({
                code: error.response?.status
            })
        }
        // 增加重试计数
        config.__retryCount++
        // 创造新的Promise来处理指数后退，为服务器提供喘息时间
        const backoff = new Promise<void>(resolve => {
            setTimeout(() => {
                resolve()
            }, this.retryDelay * config.__retryCount)
        })
        // 重新发起请求
        return backoff.then(() => {
            return this.instance(config)
        })
    }

    /**
     * 设置请求token
     * @param config axios请求配置
     */
    private setHeader(config: AxiosType): void {
        // if (config.customHeaders) {
        //     Object.keys(config.customHeaders).forEach(key => {
        //         config['headers'][key] = config.customHeaders[key]
        //     })
        // }
        config.headers['Content-Type'] = 'application/json'

        // 从 si-store 获取 tokenData
        const tokenData = siStore.get('tokenData')
        if (tokenData && tokenData.access_token) {
            !config.withoutToken && (config.headers.Authorization = `${tokenData.token_type || 'bearer'} ${tokenData.access_token}`)
        }
    }
}


export const axiosRequest = new AxiosRequest()
